package edu.amm.api;

/**
 * Конфигурация узлов сетки.
 * 
 * @author Иванов Илья
 * @since 2013-05-14
 */
public abstract class NodesConfiguration {
	
	private int segmentsCount;
	
	/**
	 * @param segmentsCount Количество отрезков разбиения.
	 */
	public NodesConfiguration(int segmentsCount) {
		if (segmentsCount < 1)
			throw new RuntimeException("Количество отрезков разбиения должно быть положительным");
		
		this.segmentsCount = segmentsCount;
	}
	
	/**
	 * @return Количество отрезков разбиения.
	 */
	public int segmentsCount() {
		return segmentsCount;
	}
	
	/**
	 * @param nodeIndex Индекс узла от 0 до {@link #segmentsCount()} включительно.
	 * @param bounds Границы для конфигурации узлов.
	 * @return Узел по индексу.
	 */
	public double node(int nodeIndex, Bounds bounds) {
		if (nodeIndex < 0 || nodeIndex > segmentsCount())
			throw new RuntimeException("Некорректный индекс узла сетки");
		if (bounds == null)
			throw new RuntimeException("Не заданы границы для конфигурации узлов");
		
		return getNode(nodeIndex, bounds);
	}
	
	/**
	 * @param nodeIndex Индекс узла от 0 до {@link #segmentsCount()} включительно.
	 * @param bounds Границы для конфигурации узлов.
	 * @return Узел по индексу.
	 */
	protected abstract double getNode(int nodeIndex, Bounds bounds);
	
	/**
	 * Равномерная конфигурация узлов.
	 * 
	 * @author Иванов Илья
	 * @since 2013-05-14 
	 */
	public static class EvenConfiguration extends NodesConfiguration {
		
		private Bounds previousBounds;
		private double step;
		
		/**
		 * @param segmentsCount Количество отрезков разбиения.
		 */
		public EvenConfiguration(int segmentsCount) {
			super(segmentsCount);
		}
		
		protected double getNode(int nodeIndex, Bounds bounds) {
			if (previousBounds != bounds) {
				step = (bounds.getRightBound() - bounds.getLeftBound()) / segmentsCount();
				previousBounds = bounds;
			}
			
			return bounds.getLeftBound() + step * nodeIndex;
		}
	}
}